package asboot.wechat.config;

import java.io.IOException;
import java.util.stream.Stream;

import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.partition.support.MultiResourcePartitioner;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.skip.AlwaysSkipItemSkipPolicy;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.database.builder.JpaItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;

import asboot.wechat.domain.Message;
import jakarta.persistence.EntityManagerFactory;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration(proxyBeanMethods = false)
public class MessagePersistStepConfig {

	@Bean
	@JobScope
	MultiResourcePartitioner multiResourcePartitioner(
			@Value("${wechat.resources.location-pattern}") String locationPattern) throws IOException {
		Resource[] resources = new PathMatchingResourcePatternResolver().getResources(locationPattern);
		Resource[] fileSystemResources = Stream.of(resources)
				.filter(item -> item instanceof FileSystemResource fsr && fsr.getFile().isFile()
						&& !fsr.getFile().getPath().contains(".svn")
						&& !fsr.getFile().getPath().contains("ダブルクォーテーション追加"))
				.sorted((a, b) -> {
					FileSystemResource fa = (FileSystemResource) a;
					FileSystemResource fb = (FileSystemResource) b;
					return Long.compare(fb.getFile().length(), fa.getFile().length());
				}).toArray(Resource[]::new);
		return new MultiResourcePartitioner() {
			{
				this.setResources(fileSystemResources);
			}
		};
	}

	@Bean
	Step messagePersistStep(JobRepository jobRepository, MultiResourcePartitioner multiResourcePartitioner,
			ThreadPoolTaskExecutor threadPoolTaskExecutor, PlatformTransactionManager transactionManager,
			FlatFileItemReader<Message> reader, JpaItemWriter<Message> writer) {
		return new StepBuilder("messagePersistStep", jobRepository)
				.partitioner("messagePartitioner", multiResourcePartitioner).gridSize(10)
				.taskExecutor(threadPoolTaskExecutor)
				.step(new StepBuilder("messagePartitionStep", jobRepository)
						.<Message, Message>chunk(10, transactionManager).reader(reader).writer(writer).faultTolerant()
						.skipPolicy(new AlwaysSkipItemSkipPolicy()).skip(Exception.class).build())
				.build();
	}

	@Bean
	@StepScope
	FlatFileItemReader<Message> headerItemReader(@Value("#{stepExecutionContext['fileName']}") Resource resource)
			throws IOException {
		log.info("resource:{}", resource);
		String url = resource.getURL().toString();
		log.info("url:{}", url);
		String fileName = resource.getFilename();
		log.info("fileName:{}", fileName);

		// @formatter:off
		return new FlatFileItemReaderBuilder<Message>()
				.resource(resource)
				.saveState(false)
				.linesToSkip(1)
//				.maxItemCount(1)
//				.lineMapper(new MetaLineMapper(type, url))
				.delimited()
				.delimiter(",")
				.names("localId","talkerId","type","subType","isSender","createTime","status","strContent","strTime","remark","nickName","sender")
				.targetType(Message.class)
				.build();
		// @formatter:on
	}

	@Bean
	JpaItemWriter<Message> jpaItemWriter(EntityManagerFactory entityManagerFactory) {
		// @formatter:off
		return new JpaItemWriterBuilder<Message>()
				.entityManagerFactory(entityManagerFactory)
				.usePersist(true)
				.build();
		// @formatter:on
	}

}
